package org.javahispano.javacup.tacticas_aceptadas.willBender.will.team;

import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.JugadorDetalle;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;

public class UtilWill {

    public static boolean rivalInterceptaTrayectoria(Posicion posSalida,
            Posicion posLlegada, SituacionPartido sp) {
        Posicion pos1;
        Posicion pos2;
        if (posSalida.getY() < posLlegada.getY()) {
            pos1 = posSalida;
            pos2 = posLlegada;
        } else {
            pos1 = posLlegada;
            pos2 = posSalida;
        }
        // Ecuación de la recta Y = ax + b || X = (y - b) / a
        double pendiente = (pos2.getY() - pos1.getY()) / (pos2.getX() - pos1.getX());
        double b = pos1.getY() - (pendiente * pos1.getX());
        Posicion[] rival = sp.rivales();
        // Recorro todos los rivales
        for (int i = 0; i < rival.length; i++) {
            if (i == UtilWill.getIndiceArqueroRival(sp)) {
                continue;
            }
            // Si la posición y del rival esta entre las posiciones y de el
            // balon y el pase
            if (rival[i].getY() > pos1.getY() && rival[i].getY() < pos2.getY()) {
                // obtengo el valor de x para la posicion y del rival
                double posX = (rival[i].getY() - b) / pendiente;
                if (rival[i].getX() > posX - ConstantesWill.deltaIntercepcion && rival[i].getX() < posX + ConstantesWill.deltaIntercepcion) {
                    // La trayectoria está interceptada por un rival
                    // System.out.println("interceptado");
                    return true;
                }
            }
        }
        return false;
    }

    public static int getIndiceArqueroRival(SituacionPartido sp) {
        JugadorDetalle[] detallesRival = sp.detalleJugadoresRivales();
        for (int i = 0; i < detallesRival.length; i++) {
            if (detallesRival[i].esPortero()) {
                return i;
            }
        }
        return -1;
    }

    public static Posicion getBalonCercano(SituacionPartido sp,
            Posicion balonPasado, double heighAnt) {
        UtilWill uw = new UtilWill();
        Ball ant = null;
        if (balonPasado != null) {
            ant = uw.new Ball();
            ant.setHeight(heighAnt);
            ant.setPos(balonPasado);
        }
        Ball now = uw.new Ball();
        now.setHeight(sp.alturaBalon());
        now.setPos(sp.balon());
        Ball res = uw.new Ball();
        for (int i = 0; i < 25; i++) {
            if (ant.getPos().distancia(now.getPos()) < 0.4) {
                res = now;
                break;
            }
            res = nextBall(ant, now);
        }
        return res.getPos();
    }

    private static Ball nextBall(Ball ant, Ball now) {
        Posicion p = new Posicion(now.getPos());
        if (ant != null) {
            double ang = ant.getPos().angulo(now.getPos());
            double avanceX = now.getPos().getX() - ant.getPos().getX();
            double avanceY = now.getPos().getY() - ant.getPos().getY();
            double velocidad = 1;

            double avanceZ = now.getHeight() - ant.getHeight();
            double dist = now.getPos().distancia(ant.getPos());
            double grav = 0;
            double angVert = 0;
            double newHeight = 0;
            if (now.getHeight() == 0) {
                velocidad = Math.sqrt(avanceX * avanceX + avanceY * avanceY) * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
            } else {
                grav = Constantes.G;
                velocidad = Math.sqrt(avanceZ * avanceZ + dist * dist) * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                angVert = Math.atan(avanceZ / dist);
                velocidad = velocidad * Math.cos(angVert);
            }
            avanceX = Math.cos(ang) * velocidad;
            avanceY = Math.sin(ang) * velocidad;
            p = p.moverPosicion(avanceX, avanceY);
            if (now.getHeight() > 0) {
                dist = p.distancia(now.getPos());
                velocidad = Math.sqrt(avanceZ * avanceZ + dist * dist) * Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                angVert = Math.atan(avanceZ / dist);
                avanceZ = Math.round(velocidad * Math.sin(angVert) / Constantes.G) * Constantes.G;
                newHeight = Math.round((now.getHeight() + avanceZ - grav) / Constantes.G) * Constantes.G;
            }
            UtilWill uw = new UtilWill();
            Ball result = uw.new Ball();
            result.setHeight(newHeight < 0 ? 0 : newHeight);
            result.setPos(p);
            return result;
        }
        return now;
    }

    public static Posicion getPosicionArquero(Posicion balonPos,
            Posicion... balonposAntA) {
        Posicion balonposAnt = (balonposAntA == null || balonposAntA.length < 1) ? Constantes.centroArcoInf
                : balonposAntA[0];
        Posicion[] rectaIntersecArquero = getLineaInterseccionArquero(balonPos);
        Posicion posIdeal = Posicion.Interseccion(rectaIntersecArquero[0],
                rectaIntersecArquero[1], balonPos, balonposAnt);
        // posIdeal = posIdeal.setPosicion(posIdeal.getX() * -1, posIdeal.getY()
        // * -1);
        if (posIdeal == null) {
            posIdeal = Constantes.cornerInfIzq;
        }
        if ((posIdeal.getX() > rectaIntersecArquero[0].getX() || posIdeal.getX() < rectaIntersecArquero[1].getX())) {
            posIdeal = Posicion.Interseccion(rectaIntersecArquero[0],
                    rectaIntersecArquero[1], balonPos,
                    Constantes.centroArcoInf);
            if (posIdeal == null) {
                posIdeal = Constantes.cornerInfIzq;
            }
            if ((posIdeal.getX() > rectaIntersecArquero[0].getX() || posIdeal.getX() < rectaIntersecArquero[1].getX())) {
                posIdeal = Constantes.centroArcoInf;
                switch (getCuadranteBalon(balonPos)) {
                    case I:
                        posIdeal = new Posicion(Constantes.posteIzqArcoInf.getX(),
                                Constantes.posteIzqArcoInf.getY() + (Constantes.ANCHO_AREA_CHICA / 3));
                        break;
                    case IV:
                        posIdeal = new Posicion(Constantes.posteDerArcoInf.getX(),
                                Constantes.posteDerArcoInf.getY() + (Constantes.ANCHO_AREA_CHICA / 3));
                        break;
                    default:
                        posIdeal = Constantes.centroArcoInf;
                        break;
                }
            }
        }
        return posIdeal;
    }

    public static Posicion[] getLineaInterseccionArquero(Posicion balonPos) {
        double nuevoY = balonPos.distancia(Constantes.centroArcoInf) / 25;
        if (nuevoY > 1) {
            return rectaIntersecArqueroDefault;
        }
        Posicion[] ret = new Posicion[]{
            new Posicion(rectaIntersecArqueroDefault[0].getX(),
            Constantes.centroArcoInf.getY() + (Constantes.ANCHO_AREA_CHICA * nuevoY)),
            new Posicion(rectaIntersecArqueroDefault[1].getX(),
            Constantes.centroArcoInf.getY() + (Constantes.ANCHO_AREA_CHICA * nuevoY)),};
        return ret;
    }

    public static CUADRANTES getCuadranteBalon(Posicion balonPos) {
        if (balonPos.getY() > (new Posicion(0, Constantes.penalSup.getY() - Constantes.ANCHO_AREA_CHICA).getY() - 4) && balonPos.getX() > Constantes.centroArcoSup.getX() - Constantes.LARGO_AREA_GRANDE / 2 && balonPos.getX() < Constantes.centroArcoSup.getX() + Constantes.LARGO_AREA_GRANDE / 2) {
            return CUADRANTES.ATAQUE;
        }
        if (balonPos.getY() > 0) {
            if (balonPos.getX() > 0) {
                return CUADRANTES.III;
            }
            return CUADRANTES.II;
        }
        if (balonPos.getX() > 0) {
            return CUADRANTES.IV;
        }
        return CUADRANTES.I;
    }

    public enum CUADRANTES {

        I, II, III, IV, ATAQUE, DEFENSA
    }
    private static Posicion[] rectaIntersecArqueroDefault = new Posicion[]{
        new Posicion(Constantes.centroArcoInf.getX() + (Constantes.LARGO_ARCO / 2), Constantes.centroArcoInf.getY() + Constantes.ANCHO_AREA_CHICA),
        new Posicion(Constantes.centroArcoInf.getX() - (Constantes.LARGO_ARCO / 2), Constantes.centroArcoInf.getY() + Constantes.ANCHO_AREA_CHICA)};

    class Ball {

        Posicion pos;
        double height;

        /**
         * @return the pos
         */
        public Posicion getPos() {
            return pos;
        }

        /**
         * @param pos
         *            the pos to set
         */
        public void setPos(Posicion pos) {
            this.pos = pos;
        }

        /**
         * @return the height
         */
        public double getHeight() {
            return height;
        }

        /**
         * @param height
         *            the height to set
         */
        public void setHeight(double height) {
            this.height = height;
        }
    }
}